﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.IO;
using PHPDecoder;

namespace CodeVisual
{
    public partial class ExportDialog : Form
    {
        String graphTemplate = null;
        String fileTemplate = null;
        String clsTemplate = null;
        String funcTemplate = null;
        String varTemplate = null;
        String callrelTemplate = null;
        Stack<string> stack = new Stack<string>();
        private int clusterIndex = 0;
        private int clusterfileIntex = 0;

        public ExportDialog()
        {
            InitializeComponent();
            Init();
            ReadTemplates();
        }

        private void ReadTemplates()
        {
            graphTemplate = ReadTemplate("dot\\graph.dot");
            fileTemplate = ReadTemplate("dot\\file.dot");
            clsTemplate = ReadTemplate("dot\\cls.dot");
            funcTemplate = ReadTemplate("dot\\func.dot");
            varTemplate = ReadTemplate("dot\\var.dot");
            callrelTemplate = ReadTemplate("dot\\callrel.dot");
        }

        private void Init()
        {
            foreach (String filename in ProjectInfo.result.decodedFile.Keys)
            {
                checkedListBox1.Items.Add(filename);
            }
            comboBox1.SelectedIndex = (int)Setting.format;
            if (Setting.funcname != null && Setting.funcname != "")
            {
                checkBox2.Checked = true;
                comboBox3.SelectedIndex = 0;
                textBox1.Text = Setting.funcname;
            }

            if (Setting.notfuncname != null && Setting.notfuncname != "")
            {
                checkBox2.Checked = true;
                comboBox3.SelectedIndex = 1;
                textBox1.Text = Setting.funcname;
            }

            checkBox5.Checked = Setting.onlyFromProject;
            checkBox3.Checked = Setting.IgnoreUnusedFunc;
            checkBox11.Checked = Setting.openAfterExport;
            checkBox9.Checked = Setting.IgnoreUnusedVar;

            if (Setting.NumCall != 0)
            {
                checkBox4.Checked = true;
                if (Setting.NumCall < 0)
                {
                    comboBox7.SelectedIndex = 0;
                }
                else
                {
                    comboBox7.SelectedIndex = 1;
                }
                numericUpDown2.Value = Math.Abs(Setting.NumCall);
            }
            
            if (Setting.NumRead != 0)
            {
                checkBox4.Checked = true;
                if (Setting.NumCall < 0)
                {
                    comboBox7.SelectedIndex = 0;
                }
                else
                {
                    comboBox7.SelectedIndex = 1;
                }
                numericUpDown2.Value = Math.Abs(Setting.NumCall);
            }
        }
        private void button1_Click(object sender, EventArgs e)
        {
            Setting.ApplyFilter(ref ProjectInfo.result);
            switch (Setting.format)
            {
                case OutputFormat.HTML:
                    GenerateHTMLOutput();
                    break;
                case OutputFormat.PDF:
                    GeneratePDFOutput();
                    break;
                case OutputFormat.SVG:
                    GenrateSVGOutput();
                    break;
            }
        }

        private void GenerateHTMLOutput()
        {
            throw new NotImplementedException();
        }
        #region Graphic_output

        private void GeneratePDFOutput()
        {
            String tmpfile = Setting.outPath + Path.DirectorySeparatorChar + "temp.dot";
            StringBuilder sb = new StringBuilder();
            sb.AppendFormat(graphTemplate, getFiles());
            sb.Replace('%', '{');
            sb.Replace('#', '}');
            using (StreamWriter sw = new StreamWriter(tmpfile))
            {
                sw.Write(sb.ToString());
            }
            
            Process p = Process.Start(@"C:\Program Files (x86)\Graphviz 2.28\bin\dot.exe", "-Tpdf -o " + Setting.outPath + Path.DirectorySeparatorChar + "output.pdf " + Setting.outPath + Path.DirectorySeparatorChar + "temp.dot");
            p.WaitForExit();
            if (Setting.openAfterExport) OpenResult();
        }
        
        private string getFiles()
        {
            StringBuilder sb = new StringBuilder();
            int index = 0;
            foreach (string s in checkedListBox1.CheckedItems)
            {
                sb.AppendFormat(fileTemplate, clusterfileIntex, Path.GetFileName(s), getClasses(s), getRelations());
                clusterfileIntex++;
            }
            return sb.ToString();
        }

        private string getRelations()
        {
            StringBuilder sb = new StringBuilder();
            while (stack.Count != 0)
            {
                sb.Append(stack.Pop());
            }

            return sb.ToString();
            //throw new NotImplementedException();
        }

        private string getClasses(string s)
        {
            StringBuilder sb = new StringBuilder();
            foreach (DataNode node in ProjectInfo.result.decodedFile[s])
            {
                if (node.tp == NodeType.CLASS)
                {
                    sb.AppendFormat(clsTemplate, clusterIndex, node.name, getFunctions((ClassNode)node), getVariables((ClassNode)node), getRelations((ClassNode)node));
                    clusterIndex++;
                }
            }
            return sb.ToString();
        }

        private string getRelations(ClassNode classNode)
        {
            StringBuilder sb = new StringBuilder();
            foreach (FunctionNode f in classNode.getFunctions().Values)
            {
                if (f.isoutput)
                {
                    foreach (FunctionNode n in f.callfuncs)
                    {
                        if (n.isoutput)
                        {
                            if (n.inCls == classNode)
                            {
                                sb.AppendFormat(callrelTemplate, f.name, n.name);
                            }
                            else
                            {
                                stack.Push(new StringBuilder().AppendFormat(callrelTemplate, f.name, n.name).ToString());
                            }
                        }
                    }
                }
            }
            return sb.ToString();
            //throw new NotImplementedException();
        }

        private string getVariables(ClassNode classNode)
        {
            StringBuilder sb = new StringBuilder();
            foreach (VariableNode node in classNode.getVariables().Values)
            {
                if (node.isoutput)
                {
                    sb.AppendFormat(varTemplate, node.name);
                }
            }
            return sb.ToString();
        }

        private string getFunctions(ClassNode classNode)
        {
            StringBuilder sb = new StringBuilder();
            foreach (FunctionNode node in classNode.getFunctions().Values)
            {
                if (node.isoutput)
                {
                    sb.AppendFormat(funcTemplate, node.name);
                }
            }
            return sb.ToString();
        }

       
        #endregion
        private String ReadTemplate(String f)
        {
            using (StreamReader sr = new StreamReader(f))
            {
                return sr.ReadToEnd();
            }
        }

        private void GenrateSVGOutput()
        {
            throw new NotImplementedException();
        }

        private void OpenResult()
        {
            Process p = null;
            switch (Setting.format)
            {
                case OutputFormat.HTML:
                    p = Process.Start(Setting.outPath + Path.DirectorySeparatorChar + "index.html");
                    break;
                case OutputFormat.PDF:
                    p = Process.Start(Setting.outPath + Path.DirectorySeparatorChar + "output.pdf");
                    break;
                case OutputFormat.SVG:
                    p = Process.Start(Setting.outPath + Path.DirectorySeparatorChar + "output.pdf");
                    break;
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            this.DialogResult = DialogResult.Cancel;
        }

        private void button4_Click(object sender, EventArgs e)
        {
            folderBrowserDialog1.ShowDialog();
            label2.Text = folderBrowserDialog1.SelectedPath;
        }

        private void checkBox10_CheckedChanged(object sender, EventArgs e)
        {
            bool b = checkBox10.Checked;
            for (int i = 0; i < checkedListBox1.Items.Count; i++)
            {
                checkedListBox1.SetItemChecked(i, b);
            }
        }

        private void button3_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < checkedListBox1.Items.Count; i++)
            {
                checkedListBox1.SetItemChecked(i, !checkedListBox1.GetItemChecked(i));
            }
        }

        private void button5_Click(object sender, EventArgs e)
        {
            Setting.Save();
        }

        private void checkBox2_CheckedChanged(object sender, EventArgs e)
        {
            if (!checkBox2.Checked)
            {
                Setting.funcname = null;
                Setting.notfuncname = null;
                return;
            }
            if (comboBox3.SelectedIndex == 0)
            {
                Setting.funcname = textBox1.Text;
            }
            else
            {
                Setting.notfuncname = textBox1.Text;
            }
        }

        private void checkBox5_CheckedChanged(object sender, EventArgs e)
        {
            Setting.onlyFromProject = checkBox5.Checked;
        }

        private void checkBox3_CheckedChanged(object sender, EventArgs e)
        {
            Setting.IgnoreUnusedFunc = checkBox3.Checked;
        }

        private void checkBox4_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBox4.Checked)
            {
                if (comboBox7.SelectedIndex == 0)
                {
                    Setting.NumCall = -(int)(numericUpDown2.Value);
                }
                else
                {
                    Setting.NumCall = (int)numericUpDown2.Value;
                }
            }
            else
            {
                Setting.NumCall = 0;
            }
        }

        private void checkBox7_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBox7.Checked)
            {
                if (comboBox4.SelectedIndex == 0)
                {
                    Setting.varname = textBox2.Text;
                }
                else
                {
                    Setting.notvarname = textBox2.Text;
                }
            }
            else
            {
                Setting.varname = null;
                Setting.notvarname = null;
            }
        }
    }
}
